package com.xunji.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xunji.user.dto.MenuDto;
import com.xunji.user.dto.RoleMenuDto;
import com.xunji.user.entity.Menu;
import com.xunji.user.entity.Role;
import com.xunji.user.entity.RoleMenu;
import com.xunji.user.mapper.RoleMapper;
import com.xunji.user.service.MenuService;
import com.xunji.user.service.RoleMenuService;
import com.xunji.user.service.RoleService;
import com.xunji.user.util.MenuUtil;
import com.xunji.user.vo.req.RoleAddRequest;
import com.xunji.user.vo.req.RoleQueryRequest;
import com.xunji.user.vo.req.RoleUpdateRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Autowired
    RoleMenuService roleMenuService;

    @Autowired
    MenuService menuService;

    @Override
    public Page<RoleMenuDto> page(RoleQueryRequest request) {
        Page<Role> page = new Page<>(request.getPageNum(), request.getPageSize());
        QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(!StringUtils.isEmpty(request.getName()), "name", request.getName());
        queryWrapper.orderByDesc("created_time");
        //角色
        Page<Role> roles = this.baseMapper.selectPage(page, queryWrapper);
        List<String> roleIds = roles.getRecords().stream().map(Role::getId).collect(Collectors.toList());
        //角色菜单
        List<RoleMenuDto> roleMenuDtos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(roleIds)) {
            List<RoleMenu> roleMenus = roleMenuService.getByRoleIds(roleIds);
            roleMenuDtos = roles.getRecords().stream().map(role -> {
                RoleMenuDto roleMenuDto = new RoleMenuDto();
                roleMenuDto.setId(role.getId());
                roleMenuDto.setName(role.getName());
                if (!CollectionUtils.isEmpty(roleMenus)) {
                    List<Integer> ids = roleMenus.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
                    //菜单详情
                    List<Menu> menus = menuService.getMenusByIds(ids);
                    Map<Integer, Menu> menuMap = menus.stream().collect(Collectors.toMap(Menu::getId, menu -> menu));
                    Map<String, List<RoleMenu>> roleMenuMap = roleMenus.stream().collect(Collectors.groupingBy(RoleMenu::getRoleId));

                    if (!CollectionUtils.isEmpty(roleMenuMap) && roleMenuMap.containsKey(role.getId())) {
                        List<RoleMenu> roleMenu = roleMenuMap.get(role.getId());
                        List<Menu> currMenus = new ArrayList<>();
                        roleMenu.stream().forEach(roleM -> {
                            Integer menuId = roleM.getMenuId();
                            if (menuMap.containsKey(menuId)) {
                                currMenus.add(menuMap.get(menuId));
                            }
                        });
                        List<MenuDto> menuDtos = currMenus.stream().map(MenuDto::getInstance).collect(Collectors.toList());
                        roleMenuDto.setMenus(MenuUtil.makePidTree(menuDtos, 0));
                    }
                }
                return roleMenuDto;
            }).collect(Collectors.toList());
        }
        Page<RoleMenuDto> responsePage = new Page<>(request.getPageNum(), request.getPageSize());
        responsePage.setTotal(roles.getTotal());
        responsePage.setRecords(roleMenuDtos);
        return responsePage;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(RoleAddRequest request) {
        Role role = Role.getInstance(request.getName());
        this.save(role);
        if (!CollectionUtils.isEmpty(request.getMenus())) {
            roleMenuService.batchSave(request.getMenus().stream().map(menuId -> RoleMenu.getInstance(role.getId(), menuId)).collect(Collectors.toList()));
        }
    }

    @Override
    public void update(RoleUpdateRequest request) {
        this.updateById(Role.getInstance(request));
        roleMenuService.deleteByRoleId(request.getId());
        if (!CollectionUtils.isEmpty(request.getMenus())) {
            roleMenuService.batchSave(request.getMenus().stream().map(menuId -> RoleMenu.getInstance(request.getId(), menuId)).collect(Collectors.toList()));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteById(String id) {
        this.removeById(id);
        roleMenuService.deleteByRoleId(id);
    }

    @Override
    public List<Role> listByIds(List<String> ids) {
        QueryWrapper<Role> qw = new QueryWrapper<Role>().in("id", ids);
        return list(qw);
    }

    @Override
    public List<Role> getRoles() {
        QueryWrapper<Role> qw = new QueryWrapper<>();
        qw.orderByDesc("created_time");
        return this.baseMapper.selectList(qw);
    }

    @Override
    public List<Role> selectByName(String name) {
        QueryWrapper<Role> qw = new QueryWrapper<Role>().eq("name", name);
        return this.baseMapper.selectList(qw);
    }

    @Override
    public List<Role> selectByNameWithoutId(String name, String id) {
        QueryWrapper<Role> qw = new QueryWrapper<Role>().eq("name", name).ne("id", id);
        return this.baseMapper.selectList(qw);
    }
}
